package com.ossfk.net.server;

import java.util.concurrent.TimeUnit;

import com.ossfk.net.config.NetServerConfig;
import com.ossfk.net.server.adapter.AbstractServerAdapter;
import com.ossfk.net.session.TcpSession;
import com.ossfk.net.session.TcpSessionManager;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.Future;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class AbstractTcpServer {
	/**
	 * 服务运行状态
	 */
	private volatile boolean isRunning = false;

	protected EventLoopGroup bossGroup = null;
	protected EventLoopGroup workerGroup = null;

	protected NetServerConfig serverConfig = null;

	/** 会话管理器 */
	private TcpSessionManager tcpSessionManager = new TcpSessionManager();

	/**
	 * 
	 * @Description: 创建一个TCP服务端,默认端口8000
	 * @author Liujiefu
	 * @date 2020-03-13 16:26:19
	 */
	public AbstractTcpServer() {
		this(null);
	}

	/**
	 * 
	 * @Description: 创建一个TCP服务端
	 * @param serverConfig
	 * @author Liujiefu
	 * @date 2020-03-13 16:26:50
	 */
	public AbstractTcpServer(NetServerConfig serverConfig) {
		super();
		if (serverConfig == null) {// 默认配置
			this.serverConfig = new NetServerConfig();
		} else {
			this.serverConfig = serverConfig;
		}
	}

	private void bind() throws Exception {
		bossGroup = new NioEventLoopGroup();
		workerGroup = new NioEventLoopGroup();
		ServerBootstrap serverBootstrap = new ServerBootstrap();
		serverBootstrap.group(bossGroup, workerGroup)//
				.channel(NioServerSocketChannel.class) //
				.childHandler(new ChannelInitializer<SocketChannel>() { //
					@Override
					public void initChannel(SocketChannel ch) throws Exception {
						ch.pipeline().addLast("idleStateHandler",
								new IdleStateHandler(serverConfig.getReaderIdleTimeSeconds(), 0, 0, TimeUnit.SECONDS));
						// ch.pipeline().addLast(new Decoder4LoggingOnly());
						DelimiterBasedFrameDecoder frameDecoder = getFrameDecoder();
						if (frameDecoder != null)
							ch.pipeline().addLast(frameDecoder);
						ByteToMessageDecoder decoder = getMsgDecoder();
						if (decoder != null) {
							ch.pipeline().addLast("decoder", decoder);
						}
						MessageToByteEncoder<?> encoder = getMsgEncoder();
						if (encoder != null) {
							ch.pipeline().addLast("encoder", encoder);
						}
						AbstractServerAdapter adapter = getChannelAdapter();
						if (adapter != null) {
							adapter.setTcpSessionManager(tcpSessionManager);
							ch.pipeline().addLast(adapter);
						}
					}
				}).option(ChannelOption.SO_BACKLOG, 128);
		if (serverConfig.isKeepAlive())
			serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
		ChannelFuture channelFuture = serverBootstrap.bind(serverConfig.getSocketAddress()).sync();
		log.info(serverConfig.getName() + " server started,SocketAddress={}",
				serverConfig.getSocketAddress().toString());
		channelFuture.channel().closeFuture().sync();
	}

	/**
	 * 启动服务
	 * 
	 * @Title: start
	 * @Description: 启动TCP服务端,并开始监听端口连接
	 * @param config 服务端配置
	 * @author Liujiefu
	 * @date 2020-03-13 15:49:26
	 */
	public synchronized void start() {
		if (isRunning) {
			// 服务已经启动无法重复启动
			throw new IllegalStateException(serverConfig.getName() + " server startup failure,server is started.");
		}
		this.isRunning = true;
		new Thread(() -> {
			try {
				this.init();
				this.bind();
			} catch (Exception e) {
				// 启动失败
				log.info("The {} is startup failure:{}", serverConfig.getName(), e.getMessage());
				e.printStackTrace();
			}
		}, serverConfig.getName()).start();

		log.info("The {} is starting...", serverConfig.getName());
	}

	/**
	 * 停止服务
	 */
	public synchronized void stop() {
		if (!isRunning) {
			// 服务无法停止
			throw new IllegalStateException(
					"The " + serverConfig.getName() + " is stop failure,server is not startup.");
		}
		try {
			Future<?> future = this.workerGroup.shutdownGracefully().await();
			if (!future.isSuccess()) {
				log.error(serverConfig.getName() + " workerGroup can not stop:{}", future.cause());
			}
			future = this.bossGroup.shutdownGracefully().await();
			if (!future.isSuccess()) {
				log.error(serverConfig.getName() + " bossGroup can not stop:{}", future.cause());
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			isRunning = false;
		}

		log.info("The {} has stopped.", serverConfig.getName());
	}

	/**
	 * 服务是否运行
	 * 
	 * @return
	 * @author Liujiefu
	 * @date 2020-03-13 16:12:08
	 */
	public boolean isRunning() {
		return isRunning;
	}

	/**
	 * 指定session发送消息
	 * @param session
	 * @param msg
	 * @author Liujiefu
	 * @date 2020-03-17 11:58:52
	 */
	public void sendMsg(TcpSession session, Object msg) {
		if (session != null && !session.isDead())
			session.getChannel().writeAndFlush(msg);
	}

	/**
	 * 
	 * @Title: init
	 * @Description: 服务启动前初始化,有需要的可以重载
	 * @author Liujiefu
	 * @date 2020-03-13 15:59:20
	 */
	public void init() {
		log.info("TcpServer {} init...{}:{}", serverConfig.getName(),serverConfig.getSocketAddress().getHostString(),serverConfig.getSocketAddress().getPort());
	}

	public TcpSessionManager getTcpSessionManager() {
		return tcpSessionManager;
	}

	public void setTcpSessionManager(TcpSessionManager tcpSessionManager) {
		this.tcpSessionManager = tcpSessionManager;
	}


	/**
	 * 分包器
	 * @return
	 * @author Liujiefu
	 * @date 2020-03-17 13:37:35
	 */
	protected abstract DelimiterBasedFrameDecoder getFrameDecoder();
	/**
	 * 解码器
	 * @return
	 * @author Liujiefu
	 * @date 2020-03-17 13:40:20
	 */
	protected abstract ByteToMessageDecoder getMsgDecoder();
	/**
	 * 编码器
	 * @return
	 * @author Liujiefu
	 * @date 2020-03-17 13:40:28
	 */
	protected abstract MessageToByteEncoder<?> getMsgEncoder();
	/**
	 * 通道处理适配
	 * @return
	 * @author Liujiefu
	 * @date 2020-03-17 13:41:15
	 */
	protected abstract AbstractServerAdapter getChannelAdapter();
}
